package com.yifi.common.plugins.IoTDB;

import com.jfinal.plugin.activerecord.Record;
import com.yifi.common.utils.JWTUtils;
import org.apache.iotdb.rpc.IoTDBConnectionException;
import org.apache.iotdb.rpc.StatementExecutionException;
import org.apache.iotdb.session.Session;
import org.apache.iotdb.session.SessionDataSet;
import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
import org.apache.iotdb.tsfile.read.common.Field;
import org.apache.iotdb.tsfile.read.common.RowRecord;
import org.apache.iotdb.tsfile.write.record.Tablet;
import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
import org.apache.log4j.Logger;

import java.rmi.ServerException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 姚善利
 * @classname com.yifi.common.utils
 * @description
 * @date 2022/10/14 15:14
 */
public class IoTDBUtils {

    static String key;

    public IoTDBUtils() {
    }

    /**
     *  root.adlot.
     * @param _key
     */
    public static IoTDBUtils use(String _key) {
        key=_key;
        return new IoTDBUtils();
    }

    private static final Logger log = Logger.getLogger(IoTDBUtils.class);

    static Session session;

    /**
     * 初始化Session
     * @param _session
     */
    public static void AddSession(Session _session) {
        if (_session == null) {
            throw new IllegalArgumentException("IoTDB Session can not be null");
        } else {
            session = _session;
        }
    }

    /**
     *  关闭Session
     * @throws IoTDBConnectionException
     */
    public static void close() throws IoTDBConnectionException {
        if (session != null) {
            session.close();
        }
    }

    /**
     *  获取Session
     * @return
     */
    public static Session getSession() {
        return session;
    }

    /**
     * description: 带有数据类型的添加操作 - insertRecord没有指定类型
     *
     * @param * @param deviceId:节点路径如：root.a1eaKSRpRty.CA3013A303A25467
     *          time:时间戳
     *          measurementsList：物理量 即：属性
     *          type：数据类型： BOOLEAN((byte)0), INT32((byte)1),INT64((byte)2),FLOAT((byte)3),DOUBLE((byte)4),TEXT((byte)5),VECTOR((byte)6);
     *          valuesList：属性值 --- 属性必须与属性值一一对应
     * @return
     */
    public static void insertRecordType(String deviceId, Long time, List<String> measurementsList, TSDataType type, List<Object> valuesList) throws StatementExecutionException, IoTDBConnectionException, ServerException {
        if (measurementsList.size() != valuesList.size()) {
            throw new ServerException("measurementsList 与 valuesList 值不对应");
        }
        List<TSDataType> types = new ArrayList<>();
        measurementsList.forEach(item -> {
            types.add(type);
        });
        session.insertRecord(deviceId, time, measurementsList, types, valuesList);
    }

    /**
     * description: 带有数据类型的添加操作 - insertRecord没有指定类型
     *
     * @param deviceId:节点路径如：root.a1eaKSRpRty.CA3013A303A25467
     * @param time:时间戳
     * @param measurementsList：物理量                             即：属性
     * @param valuesList：属性值                                   --- 属性必须与属性值一一对应
     * @return
     */
    public static void insertRecord(String deviceId, Long time, List<String> measurementsList, List<String> valuesList)
            throws StatementExecutionException, IoTDBConnectionException, ServerException {
        if (measurementsList.size() == valuesList.size()) {
            session.insertRecord(deviceId, time, measurementsList, valuesList);
        } else {
            log.error("measurementsList 与 valuesList 值不对应");
        }
    }

    /**
     * description: 批量插入
     */
    public static void insertRecords(List<String> deviceIdList, List<Long> timeList, List<List<String>> measurementsList, List<List<String>> valuesList) throws StatementExecutionException, IoTDBConnectionException, ServerException {
        if (measurementsList.size() == valuesList.size()) {
            session.insertRecords(deviceIdList, timeList, measurementsList, valuesList);
        } else {
            log.error("measurementsList 与 valuesList 值不对应");
        }
    }

    /**
     * description: 插入操作
     *
     * @param deviceId:节点路径如：root.a1eaKSRpRty.CA3013A303A25467
     * @param time:时间戳
     * @param schemaList:                                      属性值 + 数据类型 例子： List<MeasurementSchema> schemaList = new ArrayList<>();  schemaList.add(new MeasurementSchema("breath", TSDataType.INT64));
     * @param maxRowNumber：
     * @return
     */
    public static void insertTablet(String deviceId, Long time, List<MeasurementSchema> schemaList, List<Object> valueList, int maxRowNumber) throws StatementExecutionException, IoTDBConnectionException {

        Tablet tablet = new Tablet(deviceId, schemaList, maxRowNumber);
        // 向iotdb里面添加数据
        int rowIndex = tablet.rowSize++;
        tablet.addTimestamp(rowIndex, time);
        for (int i = 0; i < valueList.size(); i++) {
            tablet.addValue(schemaList.get(i).getMeasurementId(), rowIndex, valueList.get(i));
        }
        if (tablet.rowSize == tablet.getMaxRowNumber()) {
            session.insertTablet(tablet, true);
            tablet.reset();
        }
        if (tablet.rowSize != 0) {
            session.insertTablet(tablet);
            tablet.reset();
        }
    }

    /**
     * description: 根据SQL查询
     */
    public static SessionDataSet query(String sql) throws StatementExecutionException, IoTDBConnectionException {
        return session.executeQueryStatement(sql);
    }

    /**
     * description: 删除分组 如 root.a1eaKSRpRty
     *
     * @param groupName：分组名称
     * @return
     */
    public static void deleteStorageGroup(String groupName) throws StatementExecutionException, IoTDBConnectionException {
        session.deleteStorageGroup(groupName);
    }

    /**
     * description: 根据Timeseries删除  如：root.a1eaKSRpRty.CA3013A303A25467.breath  （个人理解：为具体的物理量）
     */
    public static void deleteTimeseries(String timeseries) throws StatementExecutionException, IoTDBConnectionException {
        session.deleteTimeseries(timeseries);
    }

    /**
     * description: 根据Timeseries批量删除
     */
    public static void deleteTimeserieList(List<String> timeseriesList) throws StatementExecutionException, IoTDBConnectionException {
        session.deleteTimeseries(timeseriesList);
    }

    /**
     * description: 根据分组批量删除
     */
    public static void deleteStorageGroupList(List<String> storageGroupList) throws StatementExecutionException, IoTDBConnectionException {
        session.deleteStorageGroups(storageGroupList);
    }

    /**
     * description: 根据路径和结束时间删除 结束时间之前的所有数据
     */
    public static void deleteDataByPathAndEndTime(String path, Long endTime) throws StatementExecutionException, IoTDBConnectionException {
        session.deleteData(path, endTime);
    }

    /**
     * description: 根据路径集合和结束时间批量删除 结束时间之前的所有数据
     */
    public static void deleteDataByPathListAndEndTime(List<String> pathList, Long endTime) throws StatementExecutionException, IoTDBConnectionException {
        session.deleteData(pathList, endTime);
    }

    /**
     * description: 根据路径集合和时间段批量删除
     */
    public static void deleteDataByPathListAndTime(List<String> pathList, Long startTime, Long endTime)
            throws StatementExecutionException, IoTDBConnectionException {
        session.deleteData(pathList, startTime, endTime);
    }

    /**
     *  执行语句无返回值
     * @param sql
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    public static void exesql(String sql) throws IoTDBConnectionException, StatementExecutionException {
        session.executeNonQueryStatement(sql);
    }

    /**
     *   SessionDataSet 转 List<Record>
     * @param deviceid
     * @param sessionDataSet
     * @return
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    public static List<Record> ToListRecord(String deviceid,SessionDataSet sessionDataSet) throws IoTDBConnectionException, StatementExecutionException {
        List<Record> list=new ArrayList<Record>();
        List<String> listcols = sessionDataSet.getColumnNames();    //字段信息
        sessionDataSet.setFetchSize(1); // 只一个一个的获取
        int fetchSize = sessionDataSet.getFetchSize();
        int nextNum = 0;
        while(sessionDataSet.hasNext()) {
            RowRecord next = sessionDataSet.next(); // 如果获取的数据量
            List<Field> listRes = next.getFields();     //数据信息
            Record record=new Record();
            record.set("time",next.getTimestamp());
            for (int i = 0; i < listRes.size(); i++) {
                String colname=listcols.get(i+1);
                colname = colname.substring(colname.indexOf(deviceid.replaceAll("-","_"))+deviceid.length()+1);
                Field field = listRes.get(i);
                if(field.getDataType()!=null)
                {
                    if(field.getDataType()==TSDataType.DOUBLE)
                    {
                        record.set(colname,field.getDoubleV());
                    }
                    else if(field.getDataType()==TSDataType.FLOAT)
                    {
                        record.set(colname,field.getFloatV());
                    }
                    else if(field.getDataType()==TSDataType.INT32||field.getDataType()==TSDataType.INT64)
                    {
                        record.set(colname,field.getIntV());
                    }
                    else if(field.getDataType()==TSDataType.BOOLEAN)
                    {
                        record.set(colname,field.getBoolV());
                    }
                    else if(field.getDataType()==TSDataType.TEXT)
                    {
                        record.set(colname,field.getStringValue());
                    }
                    else
                    {
                        record.set(colname,field.getStringValue());
                    }
                }
                else
                {
                    record.set(colname,null);
                }
            }
            list.add(record);
            nextNum++;
        }
        sessionDataSet.closeOperationHandle();
        return list;
    }

    /**
     *  查询出单参数的时间折线图数据集
     * @param deviceid
     * @param sessionDataSet
     * @return
     * @throws IoTDBConnectionException
     * @throws StatementExecutionException
     */
    public static List<Object> ToList(String deviceid,SessionDataSet sessionDataSet) throws IoTDBConnectionException, StatementExecutionException {

        List<Object> data;
        List<Object> list_data = new ArrayList<Object>();

        List<String> listcols = sessionDataSet.getColumnNames();    //字段信息
        sessionDataSet.setFetchSize(1); // 只一个一个的获取
        int fetchSize = sessionDataSet.getFetchSize();
        int nextNum = 0;
        while(sessionDataSet.hasNext()) {
            RowRecord next = sessionDataSet.next(); // 如果获取的数据量
            List<Field> listRes = next.getFields();     //数据信息
            data=new ArrayList<Object>();
            data.add(next.getTimestamp());              //时间
            for (int i = 0; i < listRes.size(); i++) {
                String colname=listcols.get(i+1);
                colname = colname.substring(colname.indexOf(deviceid.replaceAll("-","_"))+deviceid.length()+1);
                Field field = listRes.get(i);
                if(field.getDataType()!=null)
                {
                    if(field.getDataType()==TSDataType.DOUBLE)
                    {
                        data.add(field.getDoubleV());
                    }
                    else if(field.getDataType()==TSDataType.FLOAT)
                    {
                        data.add(field.getFloatV());
                    }
                    else if(field.getDataType()==TSDataType.INT32||field.getDataType()==TSDataType.INT64)
                    {
                        data.add(field.getIntV());
                    }
                }
                else
                {
                    data.add(null);
                }
            }
            list_data.add(data);
            nextNum++;
        }
        sessionDataSet.closeOperationHandle();
        return list_data;
    }
}
